README

Populism and Academic Freedom
February 2026

///////////////////////////////////////////

SOURCES: 

Data on voting (seats, ideology, elections, cabinets, etc) come from ParlGov Project (https://www.parlgov.org/) and their most recent database (ParlGov 2024), completed with information extracted from Nordsieck (2025). 

Data on GDP and population size come from the IMF (https://www.imf.org/en/Data) and was retrieved in May 2025. 

Data on average precipitation and temperature was extracted from open-meteo using ERA5 data (open-meteo.com). Data was collected for each election day for the capital (or most populous city) of each region at NUTS II level (except for the UK where NUTS I is representative of the country) from https://ec.europa.eu/eurostat/databrowser/view/demo_r_pjangroup/default/table?lang=en in May 2025. The data was collected using their respective library in Python. Below, we provide an example of the code:

--

CODE TO EXTRACT WEATHER DATA

 import pandas as pd
 from openmeteo_requests import Client
 import requests_cache
 from retry_requests import retry

 #API client
 cache_session = requests_cache.CachedSession('.cache',expire_after=-1)
 retry_session = retry(cache_session, retries=5, backoff_factor=0.2)
 openmeteo = Client(session=retry_session)

 #API call
 url = "https://archive-api.open-meteo.com/v1/archive"
 params = {
      "latitude": [insert latitudes]
      "longitude": [insert longitudes]
      "start_date":"date"
      "end_date":"date"
      "daily": ["precipitation_sum"]
      "timezone": "auto"
 }

 responses = openmeteo.weather_api(url,params=params)
 
 location_metadata = []
 daily_weather_data = []

 for i, response in enumerate(responses):
 #save metadata
 location_metadata.append({
       "location_id":i,
       "latitude": response.Latitude(),
       "longitude": response.Longitude(),
       "elevation": response.Elevation(),
       "utc_offset": response.UtcOffsetSeconds(),
       "timezone": response.Timezone(),
       "timezone_abbreviation": response.TimezoneAbbreviation()
 })

 # Extract daily values
    daily = response.Daily()
    dates = pd.date_range(
        start=pd.to_datetime(daily.Time(), unit="s", utc=True),
        end=pd.to_datetime(daily.TimeEnd(), unit="s", utc=True),
        freq=pd.Timedelta(seconds=daily.Interval()),
        inclusive="left"
    )

    df = pd.DataFrame({
        "location_id": i,
        "time": dates.date,
        "precipitation_sum (mm)": daily.Variables(0).ValuesAsNumpy(),
        "temperature_2m_mean (°C)": daily.Variables(1).ValuesAsNumpy(),
        "sunshine_duration (s)": daily.Variables(2).ValuesAsNumpy()
    })

    daily_weather_data.append(df)

 #Convert lists to DataFrames
 metadata_df = pd.DataFrame(location_metadata)
 weather_df = pd.concat(daily_weather_data, ignore_index=True)

 #Save to Excel with two sheets
with pd.ExcelWriter("weather_data_all_locations.xlsx", engine="xlsxwriter") as writer:
        metadata_df.to_excel(writer, sheet_name="locations", index=False)
        weather_df.to_excel(writer, sheet_name="daily_weather", index=False)

print("Excel file 'weather_data.xlsx' generated successfully.")

--

Data on the population of each region was obtained from the Eurostat with reference to 2013 (approximately, the middle point of our time series). For example, the average temperature in a country i with J regions j in day t is calculated as: 

average temperature = \sum_{j=1}^{J} share of the population in region j \times mean temperature in that region in day t

///////////////////////////////////////////

MAPS - AVERAGE TEMPERATURE

import geopandas as gpd
import matplotlib.pyplot as plt
import pandas as pd


shapefile = r"C:\Users\drj21nqu\OneDrive - University of East Anglia\shapefile\ne_110m_admin_0_countries.shp"
world = gpd.read_file(shapefile)

europe = world[world['CONTINENT'] == 'Europe'].copy()
import matplotlib.colors as mcolors


continuous_data = {
    'Austria': 10.848005,
    'Belgium': 14.5352,
    'Bulgaria': 14.978899,
    'Croatia': 12.514592,
    'Cyprus': 24.65,
    'Czechia': 14.509203,
    'Denmark': 7.3312533,
    'Estonia': -0.85000002,
    'Finland': 0.71485192,
    'France': 19.395802,
    'Germany': 13.881293,
    'Greece': 20.536538,
    'Hungary': 12.230606,
    'Iceland': 4.9555557,
    'Ireland': 10.3086636,
    'Italy': 12.167165,
    'Latvia': 9.2777776,
    'Lithuania': 7.2154823,
    'Luxembourg': 14.8333333,
    'Netherlands': 10.017476,
    'Norway': 12.283587,
    'Poland': 10.077344,
    'Portugal': 16.379163,
    'Romania': 4.5454836,
    'Slovakia': 12.67948,
    'Slovenia': 13.216501,
    'Spain': 14.317188,
    'Sweden': 13.095015,
    'Switzerland': 8.4236776,
    'United Kingdom': 10.859659,
}
df = pd.DataFrame(continuous_data.items(), columns=['NAME', 'value'])

# Merge with shapefile
selected = europe.merge(df, on='NAME', how='inner')
selected = selected.explode(index_parts=False).reset_index(drop=True)

# Project to EPSG:3035 for centroid calculation
selected_proj = selected.to_crs(epsg=3035)
centroids = selected_proj.geometry.centroid.to_crs(selected.crs)

# Remove Canary Islands (lat < 30, lon < -10)
selected = selected[~((centroids.y < 30) & (centroids.x < -10))]

# Red color gradient
cmap = plt.cm.Reds
norm = mcolors.Normalize(vmin=selected['value'].min(), vmax=selected['value'].max())

# Plot
fig, ax = plt.subplots(figsize=(8, 6))
selected.plot(
    column='value',
    cmap=cmap,
    norm=norm,
    edgecolor='white',
    linewidth=0.6,
    ax=ax
)

# Colorbar
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
sm._A = []
cbar = fig.colorbar(sm, ax=ax, fraction=0.03, pad=0.04)
cbar.set_label('', rotation=270, labelpad=15)

# Zoom
minx, miny, maxx, maxy = selected.total_bounds
ax.set_xlim(minx, maxx)
ax.set_ylim(miny, maxy)

plt.title("Average Temperature", fontsize=16, loc='center', pad=20)
plt.axis('off')

plt.savefig("europe_temperature_continuous.png", dpi=300, bbox_inches='tight', pad_inches=0.1)
plt.show()

///////////////////////////////////////////

MAPS - AVERAGE PRECIPITATION


import geopandas as gpd
import matplotlib.pyplot as plt
import pandas as pd


shapefile = r"C:\Users\drj21nqu\OneDrive - University of East Anglia\shapefile\ne_110m_admin_0_countries.shp"
world = gpd.read_file(shapefile)

europe = world[world['CONTINENT'] == 'Europe'].copy()
import matplotlib.colors as mcolors

continuous_data = {
    'Austria': 1.1517763,
    'Belgium': 1.2442784,
    'Bulgaria': 1.7543383,
    'Croatia': 3.4954919,
    'Cyprus': 0.0333333,
    'Czechia': 0.67377281,
    'Denmark': 0.81594525,
    'Estonia': 0.43750001,
    'Finland': 0.89010753,
    'France': 2.4251065,
    'Germany': 1.6505973,
    'Greece': 0.34485182,
    'Hungary': 1.485862,
    'Iceland': 2.9666667,
    'Ireland': 9.3944217,
    'Italy': 4.8469137,
    'Latvia': 6.01111112,
    'Lithuania': 3.079518,
    'Luxembourg': 1.65,
    'Netherlands': 2.0553216,
    'Norway': 7.5334098,
    'Poland': 1.013331,
    'Portugal': 4.2496778,
    'Romania': 5.1351055,
    'Slovakia': 0.9871056,
    'Slovenia': 2.0543069,
    'Spain': 1.7627329,
    'Sweden': 0.92884676,
    'Switzerland': 2.3342289,
    'United Kingdom': 2.6178077,
}
df = pd.DataFrame(continuous_data.items(), columns=['NAME', 'value'])

# Merge with shapefile
selected = europe.merge(df, on='NAME', how='inner')
selected = selected.explode(index_parts=False).reset_index(drop=True)

# Project to EPSG:3035 for centroid calculation
selected_proj = selected.to_crs(epsg=3035)
centroids = selected_proj.geometry.centroid.to_crs(selected.crs)

# Remove Canary Islands (lat < 30, lon < -10)
selected = selected[~((centroids.y < 30) & (centroids.x < -10))]

# Red color gradient
cmap = plt.cm.Blues
norm = mcolors.Normalize(vmin=selected['value'].min(), vmax=selected['value'].max())

# Plot
fig, ax = plt.subplots(figsize=(8, 6))
selected.plot(
    column='value',
    cmap=cmap,
    norm=norm,
    edgecolor='white',
    linewidth=0.6,
    ax=ax
)

# Colorbar
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
sm._A = []
cbar = fig.colorbar(sm, ax=ax, fraction=0.03, pad=0.04)
cbar.set_label('', rotation=270, labelpad=15)

# Zoom
minx, miny, maxx, maxy = selected.total_bounds
ax.set_xlim(minx, maxx)
ax.set_ylim(miny, maxy)

plt.title("Average Precipitation", fontsize=16, loc='center', pad=20)
plt.axis('off')

plt.savefig("europe_precipitation_continuous.png", dpi=300, bbox_inches='tight', pad_inches=0.1)
plt.show()


///////////////////////////////////////////

CITIES USED WHEN CONSTRUCTING THE WEATHER VARIABLES

Eisenstadt
St. Polten
Vienna
Klagenfurt
Graz
Linz
Salzburg
Innsbruck
Bregenz
Brussels 
Antwerp
Hasselt
Ghent
Leuven
Bruges
Wavre
Mons
Liege
Arlon
Namur
Pleven
Ruse
Varna
Burgas
Sofia
Plovdiv
Nicosia
Prague
Ceske Budejovice
Plzen
Hradec Kralove
Brno
Olomouc
Ostrava
Stuttgart
Karlsruhe
Freiburg
Tubingen
Munich
Landshut
Regensburg
Bayreuth
Ansbach
Wurzburg
Augsburg
Berlin
Potsdam
Bremen
Hamburg
Darmstadt
Giessen
Kassel
Rostock
Braunschweig
Hanover
Luneburg
Oldenburg
Dusseldorf
Cologne
Munster
Detmold
Arnsberg
Koblenz
Trier
Neustadt
Saarbrucken
Chemnitz
Dresden
Leipzig
Halle (Salle)
Kiel
Erfurt
Copenhagen
Soro
Vejle
Viborg
Aalborg
Tallinn
Athens
Mytilene
Rhodes
Heraklion
Komotini
Thessaloniki
Kozani
Ioannina
Larissa
Corfu
Patras
Lamia
Tripoli
Santiago
Oviedo
Santander
Bilbao
Pamplona
Logrono
Zaragoza
Madrid
Valladolid
Toledo
Merida
Barcelona
Valencia
Palma
Seville
Tenerife 
(excludes Ceuta and Melilla)
Kuopio
Helsinki
Tampere
Oulu
(excludes Aland)
Paris
Orleans
Dijon
Besancon
Caen
Rouen
Lille
Amiens
Strasbourg
Auvergne
Metz
Nantes
Rennes
Bordeaux
Limoges
Poitiers
Montpellier
Toulouse
Lyon
Marseille
(excludes outre Mer and Corsica)
Osijek
Dubrovnik
Zagreb
Budapest
Szekesfehervar
Gyor
Pecs
Miskolc
Debrecen
Szeged
Dublin
Galway
Cork
Aosta
Genoa
Milan
Turin
Bologna
Trieste
Trento
Venice
Rome
Ancona
Florence
Perugia
L'Aquila
Bari
Potenza
Catanzaro
Naples
Campobasso
Cagliari
Palermo
Vilnius
Kaunas
Luxembourg
Riga
Groningen
Leeuwarder
Assen
Zwolle
Arnheim
Lelystad
Utrecht
Haarlem
The Hague
Middelburg
S-Hertogenbosch
Maastricht
Krakow
Katowice
Poznan
Gorzow
Szczecin
Wroclaw
Opole
Bydgoszcz
Gdansk
Olsztyn
Kielce
Lodz
Lublin
Bialystok
Rzeszow
Warsaw
Porto
Faro
Coimbra
Lisbon
Evora
(excludes Acores and Madeira)
Cluj
Brasov
Iasi
Constanta
Ploiesti
Bucharest
Craiova
Timisoara
Stockholm
Uppsala
Jonkoping
Malmo
Gothenburg
Gavle
Sundsvall
Umea
Maribor
Ljubljana
Bratislava
Bauska Bystrica
Kosice
Geneve
Bern
Basel
Zurich
St. Gallen
Luzerne
Lugano
Reykjavik
Oslo
Lillehammer
Kristiansand
Bergen 
Steinkjer
Tromso
Newcastle
Manchester
Leeds
Nottingham
Birmingham 
Cambridge 
London
Brighton 
Bristol
Cardiff
Edinburgh
Belfast 

///////////////////////////////////////////

GENERAL ELECTIONS [WE ONLY CONSIDER THE LAST ELECTION BEFORE THE END OF A CIVIL YEAR]

AUSTRIA
17/12/1995
03/10/1999
24/11/2002
01/10/2006
28/09/2008
29/09/2013
15/10/2017
29/09/2019
29/09/2024

BELGIUM
21/05/1995
13/06/1999
18/05/2003
10/06/2007
13/06/2010
25/05/2014
26/05/2019
09/06/2024

BULGARIA
18/12/1994
19/04/1997
17/06/2001
25/05/2005
05/07/2009
12/05/2013
05/10/2014
26/03/2017
14/11/2021
02/10/2022
02/04/2023
27/10/2024

CYPRUS
19/05/1991
26/05/1996
27/05/2001
21/05/2006
22/05/2011
22/05/2016
30/05/2021

CZECH REPUBLIC
05/06/1992 \& 06/06/1992
31/05/1996 \& 01/06/1996
19/06/1998 \& 20/06/1998
14/06/2002 \& 15/06/2002
02/06/2006 \& 03/06/2006
28/05/2010 \& 29/05/2010
25/10/2013 \& 26/10/2013
20/10/2017 \& 21/10/2017
08/10/2021 \& 09/10/2021

CROATIA
29/10/1995
03/01/2000
23/11/2003
25/11/2007
04/12/2011
08/11/2015
11/09/2016
05/07/2020
17/04/2024

DENMARK
21/09/1994
11/03/1998
20/11/2001
08/02/2005
13/11/2007
15/09/2011
18/06/2015
05/06/2019
01/11/2022

ESTONIA
05/03/1995
07/03/1999
02/03/2003
04/03/2007
06/03/2011
01/03/2015
03/03/2019
05/03/2023

FINLAND
19/03/1995
21/03/1999
16/03/2003
18/03/2007
17/04/2011
19/04/2015
14/04/2019
02/04/2023

FRANCE
28/03/1993
01/06/1997
16/06/2002
17/06/2007
17/06/2012
18/06/2017
19/06/2022
07/07/2024

GERMANY
16/10/1994
27/09/1998
22/09/2002
18/09/2005
27/09/2009
22/09/2013
24/09/2017
26/09/2021

GREECE
10/10/1993
22/09/1996
09/04/2000
07/03/2004
16/09/2007
04/10/2009
17/06/2012
20/09/2015
07/07/2019
25/06/2023

HUNGARY
29/05/1994
2/05/1998
21/04/2002
23/04/2006
25/04/2010
06/04/2014
08/04/2018
03/04/2022

ICELAND
08/04/1995
08/05/1999
10/05/2003
12/05/2007
25/04/2009
27/04/2013
29/10/2016
28/10/2017
25/09/2021
30/11/2024

IRELAND
25/11/1992
06/06/1997
17/05/2002
24/05/2007
25/02/2011
26/02/2016
08/02/2020
29/11/2024

ITALY
28/03/1994
21/04/1996
13/05/2001
10/04/2006
14/04/2008
25/02/2013
04/03/2018
25/09/2022

LATVIA
01/10/1995
03/10/1998
05/10/2002
07/10/2006
02/10/2010
17/09/2011
04/10/2014
06/10/2018
01/10/2022

LITHUANIA
15/11/1992
10/11/1996
08/10/2000
24/10/2004
26/10/2008
28/10/2012
23/10/2016
25/10/2020
27/10/2024

LUXEMBOURG
12/06/1994
13/06/1999
13/06/2004
07/06/2009
20/10/2013
14/10/2018
08/10/2023

NETHERLANDS
03/05/1994
06/05/1998
15/05/2002
22/01/2003
22/11/2006
09/06/2010
12/09/2012
15/03/2017
17/03/2021
22/11/2023

NORWAY
13/09/1993
15/09/1997
10/09/2001
12/09/2005
14/09/2009
09/09/2013
11/09/2017
13/09/2021

POLAND
19/09/1993
21/09/1997
23/09/2001
25/09/2005
21/10/2007
09/10/2011
25/10/2015
12/10/2019
15/10/2023

PORTUGAL
01/10/1995
10/10/1999
17/03/2002
20/02/2005
27/09/2009
05/06/2011
04/10/2015
06/10/2019
30/01/2022
10/03/2024

ROMANIA
27/09/1992
03/11/1996
26/11/2000
28/11/2004
30/11/2008
09/12/2012
11/12/2016
06/12/2020
01/12/2024

SLOVAKIA
01/10/1994
26/09/1998
21/09/2002
17/06/2006
12/06/2010
10/03/2012
05/03/2016
29/02/2020
30/09/2023

SLOVENIA
10/12/1992
10/11/1996
15/10/2000
03/10/2004
21/09/2008
04/12/2011
13/07/2014
03/06/2018
24/04/2022

SPAIN
06/06/1993
03/03/1996
12/03/2000
14/03/2004
09/03/2008
20/11/2011
20/12/2015
26/06/2016
10/11/2019
23/07/2023

SWEDEN
18/09/1994
20/09/1998
15/09/2002
17/09/2006
19/09/2010
14/09/2014
09/09/2018
11/09/2022

SWITZERLAND
22/10/1995
24/10/1999
19/10/2003
21/10/2007
23/10/2011
18/10/2015
20/10/2019
22/10/2023

UK
09/04/1992
01/05/1997
07/06/2001
05/05/2005
06/05/2010
07/05/2015
08/06/2017
12/12/2019
04/07/2024

